package com.pomelo.tool.service;

import java.io.File;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.stereotype.Service;
import org.tmatesoft.svn.core.SVNDepth;
import org.tmatesoft.svn.core.SVNURL;
import org.tmatesoft.svn.core.internal.io.svn.SVNRepositoryFactoryImpl;
import org.tmatesoft.svn.core.internal.wc.DefaultSVNOptions;
import org.tmatesoft.svn.core.wc.ISVNOptions;
import org.tmatesoft.svn.core.wc.SVNClientManager;
import org.tmatesoft.svn.core.wc.SVNRevision;
import org.tmatesoft.svn.core.wc.SVNStatus;
import org.tmatesoft.svn.core.wc.SVNStatusType;
import org.tmatesoft.svn.core.wc.SVNUpdateClient;
import org.tmatesoft.svn.core.wc.SVNWCUtil;

/**
 * svn操作
 *
 * @author biankudingcha
 * @date: 2021-10-05
 * @since 0.5.0
 */
@Service
public class SvnService {

    private static transient Log LOGGER = LogFactory.getLog(SvnService.class);

    private SVNClientManager clientManager;

    /**
     * 检出
     *
     * @param username 用户名
     * @param password 密码
     * @param sourceSvnPath svn路径
     * @param checkOutDir 检出路径
     * @throws Exception
     */
    public void checkOut(String username, String password, String sourceSvnPath, String checkOutDir) throws Exception {
        // 初始化支持svn://协议的库。 必须先执行此操作。
        SVNRepositoryFactoryImpl.setup();
        // 相关变量赋值
        SVNURL repositoryURL = SVNURL.parseURIEncoded(sourceSvnPath);
        ISVNOptions options = SVNWCUtil.createDefaultOptions(true);
        // 实例化客户端管理类
        this.clientManager = SVNClientManager.newInstance((DefaultSVNOptions) options, username, password);
        // 要把版本库的内容check out到的目录
        File wcDir = new File(checkOutDir);
        // 通过客户端管理类获得updateClient类的实例。
        SVNUpdateClient updateClient = this.clientManager.getUpdateClient();
        // sets externals not to be ignored during the checkout
        updateClient.setIgnoreExternals(false);
        // 执行check out操作，返回工作副本的版本号。
        long workingVersion = updateClient.doCheckout(repositoryURL, wcDir, SVNRevision.HEAD, SVNRevision.HEAD,
            SVNDepth.INFINITY, false);
        LOGGER.info("VERSION：" + workingVersion + "check out to " + wcDir);
    }

    /**
     * 更新
     *
     * @param username 用户名
     * @param password 密码
     * @param sourceSvnPath svn路径
     * @param checkOutDir 检出路径
     * @throws Exception
     */
    public void update(String username, String password, String sourceSvnPath, String checkOutDir) throws Exception {
        // 初始化支持svn://协议的库。 必须先执行此操作。
        SVNRepositoryFactoryImpl.setup();
        // 相关变量赋值
        SVNURL.parseURIEncoded(sourceSvnPath);
        ISVNOptions options = SVNWCUtil.createDefaultOptions(true);
        // 实例化客户端管理类
        this.clientManager = SVNClientManager.newInstance((DefaultSVNOptions) options, username, password);
        // 要更新的文件
        File updateFile = new File(checkOutDir);
        // 获得updateClient的实例
        SVNUpdateClient updateClient = this.clientManager.getUpdateClient();
        updateClient.setIgnoreExternals(false);
        // 执行更新操作
        long versionNum = updateClient.doUpdate(updateFile, SVNRevision.HEAD, SVNDepth.INFINITY, false, false);
        LOGGER.info(sourceSvnPath + "更新成功;updated version is " + versionNum);
    }

    /**
    * 提交
    *
    * @param username 用户名
    * @param password 密码
    * @param sourceSvnPath svn路径
    * @param checkOutDir 检出路径
    * @throws Exception
    */
    public void commit(String username, String password, String sourceSvnPath, String checkOutDir) throws Exception {
        // 初始化支持svn://协议的库。 必须先执行此操作。
        SVNRepositoryFactoryImpl.setup();
        // 相关变量赋值
        SVNURL.parseURIEncoded(sourceSvnPath);
        ISVNOptions options = SVNWCUtil.createDefaultOptions(true);
        // 实例化客户端管理类
        this.clientManager = SVNClientManager.newInstance((DefaultSVNOptions) options, username, password);
        // 要提交的文件
        File commitFile = new File(checkOutDir);
        // 获取此文件的状态（是文件做了修改还是新添加的文件？）
        SVNStatus status = this.clientManager.getStatusClient().doStatus(commitFile, true);
        // 如果此文件是新增加的则先把此文件添加到版本库，然后提交。
        if (status.getContentsStatus() == SVNStatusType.STATUS_UNVERSIONED) {
            // 把此文件增加到版本库中
            this.clientManager.getWCClient().doAdd(commitFile, false, false, false, SVNDepth.INFINITY, false, false);
            // 提交此文件
            this.clientManager.getCommitClient().doCommit(new File[] { commitFile }, true, "", null, null, true, false,
                SVNDepth.INFINITY);
        } else {
            // 如果此文件不是新增加的，直接提交。
            this.clientManager.getCommitClient().doCommit(new File[] { commitFile }, true, "", null, null, true, false,
                SVNDepth.INFINITY);
        }
        LOGGER.info("commit status " + status.getContentsStatus());

    }
}
